1 module models;
2 
3 import std.typecons : Nullable;
4 import std.json : JSONValue, JSONType, parseJSON;
5 import std.format;
6 import std.algorithm : map;
7 import std.array : array;
8 import std.traits;
9 import std.meta : Filter, staticMap;
10 
11 enum AlignContent: string {
12     flexStart = "flex-start",
13     flexEnd = "flex-end",
14     center = "center",
15     spaceBetween = "space-between",
16     spaceAround = "space-around",
17     spaceEvenly = "space-evenly",
18     stretch = "stretch",
19     inherit = "inherit",
20     initial = "initial",
21     unset = "unset"
22 }
23 
24 enum AlignItems: string {
25     flexStart = "flex-start",
26     flexEnd = "flex-end",
27     center = "center",
28     baseline = "baseline",
29     stretch = "stretch",
30     inherit = "inherit",
31     initial = "initial",
32     unset = "unset"
33 }
34 
35 enum AlignSelf: string {
36     auto_ = "auto",
37     flexStart = "flex-start",
38     flexEnd = "flex-end",
39     center = "center",
40     baseline = "baseline",
41     stretch = "stretch",
42     inherit = "inherit",
43     initial = "initial",
44     unset = "unset"
45 }
46 
47 enum JustifyContent: string {
48     flexStart = "flex-start",
49     flexEnd = "flex-end",
50     center = "center",
51     spaceBetween = "space-between",
52     spaceAround = "space-around",
53     inherit = "inherit",
54     initial = "initial",
55     unset = "unset"
56 }
57 
58 enum Overflow: string {
59     visible = "visible",
60     hidden = "hidden",
61     scroll = "scroll",
62     auto_ = "auto",
63     inherit = "inherit",
64     initial = "initial",
65     unset = "unset"
66 }
67 
68 enum Visibility: string {
69     visible = "visible",
70     hidden = "hidden",
71     inherit = "inherit",
72     initial = "initial",
73     unset = "unset"
74 }
75 
76 enum BoxStyle: string {
77     success = "success",
78     info = "info",
79     warning = "warning",
80     danger = "danger",
81     none = ""
82 }
83 
84 enum ButtonStyle: string {
85     primary = "primary",
86     success = "success",
87     info = "info",
88     warning = "warning",
89     danger = "danger",
90     none = ""
91 }
92 
93 enum Orientation : string {
94     horizontal = "horizontal",
95     vertical = "vertical"
96 }
97 // NOTE: the enums above aren't used in the models below. Instead plain strings are used.
98 // This is because of https://issues.dlang.org/show_bug.cgi?id=20410
99 // Effectively sumtype (by use of ReplaceTypeUnless) decays them into string, causing errors
100 
101 // Models can reference to another Widget. The reference is a prepended string to a Widget's commId
102 auto makeReference(string commId) @safe {
103     return "IPY_MODEL_"~commId;
104 }
105 
106 struct Reference(T) {
107     string value;
108     alias value this;
109 }
110 
111 alias typeOf(alias T) = typeof(T);
112 // To instantiate a Widget!Model we need to also instantiate a Widget!T for each model that is referenced.
113 // This template exposed Names and Types which contain the name and type of each Referenced model for a given Model.
114 template getReferenceModels(T) {
115     enum isReference(string name) = is(typeof(__traits(getMember, T, name)) : Reference!R, R);
116     alias getSymbol(string name) = __traits(getMember, T, name);
117     alias extractModelType(T) = TemplateArgsOf!(T)[0];
118     alias Names = Filter!(isReference, __traits(allMembers, T));
119     alias Types = staticMap!(extractModelType, staticMap!(typeOf,staticMap!(getSymbol,  Names)));
120 }
121 
122 alias BarStyle = BoxStyle;
123 
124 struct LayoutModel {
125     enum _model_module = "@jupyter-widgets/base"; // The namespace for the model.
126     enum _model_module_version = "1.0.0"; // A semver requirement for namespace version containing the model.
127     enum _model_name = "LayoutModel";
128     enum _view_module = "@jupyter-widgets/base";
129     enum _view_module_version = "1.0.0";
130     enum _view_name = "LayoutView";
131     Nullable!(string) align_content; // The align-content CSS attribute.
132     Nullable!(string) align_items; // The align-items CSS attribute.
133     Nullable!(string) align_self; // The align-self CSS attribute.
134     Nullable!(string) border; // The border CSS attribute.
135     Nullable!(string) bottom; // The bottom CSS attribute.
136     Nullable!(string) display; // The display CSS attribute.
137     Nullable!(string) flex; // The flex CSS attribute.
138     Nullable!(string) flex_flow; // The flex-flow CSS attribute.
139     Nullable!(string) height; // The height CSS attribute.
140     Nullable!(string) justify_content; // The justify-content CSS attribute.
141     Nullable!(string) left; // The left CSS attribute.
142     Nullable!(string) margin; // The margin CSS attribute.
143     Nullable!(string) max_height; // The max-height CSS attribute.
144     Nullable!(string) max_width; // The max-width CSS attribute.
145     Nullable!(string) min_height; // The min-height CSS attribute.
146     Nullable!(string) min_width; // The min-width CSS attribute.
147     Nullable!(string) order; // The order CSS attribute.
148     Nullable!(string) overflow; // The overflow CSS attribute.
149     Nullable!(string) overflow_x; // The overflow-x CSS attribute.
150     Nullable!(string) overflow_y; // The overflow-y CSS attribute.
151     Nullable!(string) padding; // The padding CSS attribute.
152     Nullable!(string) right; // The right CSS attribute.
153     Nullable!(string) top; // The top CSS attribute.
154     Nullable!(string) visibility; // The visibility CSS attribute.
155     Nullable!(string) width; // The width CSS attribute.
156 }
157 
158 // TODO: WidgetModel[] is not implemented. Probably could be a IWidget[]
159 // struct AccordionModel {
160 //     string[] _dom_classes; // CSS classes applied to widget DOM element
161 //     enum _model_module = "@jupyter-widgets/controls";
162 //     enum _model_module_version = "1.2.0";
163 //     enum _model_name = "AccordionModel";
164 //     JSONValue _titles = {}; // Titles of the pages
165 //     enum _view_module = "@jupyter-widgets/controls";
166 //     enum _view_module_version = "1.2.0";
167 //     enum _view_name = "AccordionView";
168 //     string box_style = BoxStyle.none; // Use a predefined styling for the box.
169 //     WidgetModel[] children; // List of widget children
170 //     Reference!LayoutModel layout;
171 //     Nullable!(int) selected_index = 0; // The index of the selected page. This is either an integer selecting a particular sub-widget, or None to have no widgets selected.
172 // }
173 
174 struct BoundedFloatTextModel {
175     string[] _dom_classes; // CSS classes applied to widget DOM element
176     enum _model_module = "@jupyter-widgets/controls";
177     enum _model_module_version = "1.2.0";
178     enum _model_name = "BoundedFloatTextModel";
179     enum _view_module = "@jupyter-widgets/controls";
180     enum _view_module_version = "1.2.0";
181     enum _view_name = "FloatTextView";
182     bool continuous_update = false; // Update the value as the user types. If False, update on submission, e.g., pressing Enter or navigating away.
183     string description; // Description of the control.
184     bool disabled = false; // Enable or disable user changes
185     Reference!LayoutModel layout;
186     double max = 100.0; // Max value
187     double min = 0.0; // Min value
188     Nullable!(double) step; // Minimum step to increment the value
189     Reference!DescriptionStyleModel style; // Styling customizations
190     double value = 0.0; // Float value
191 }
192 
193 struct BoundedIntTextModel {
194     string[] _dom_classes; // CSS classes applied to widget DOM element
195     enum _model_module = "@jupyter-widgets/controls";
196     enum _model_module_version = "1.2.0";
197     enum _model_name = "BoundedIntTextModel";
198     enum _view_module = "@jupyter-widgets/controls";
199     enum _view_module_version = "1.2.0";
200     enum _view_name = "IntTextView";
201     bool continuous_update = false; // Update the value as the user types. If False, update on submission, e.g., pressing Enter or navigating away.
202     string description; // Description of the control.
203     bool disabled = false; // Enable or disable user changes
204     Reference!LayoutModel layout;
205     int max = 100; // Max value
206     int min = 0; // Min value
207     int step = 1; // Minimum step to increment the value
208     Reference!DescriptionStyleModel style; // Styling customizations
209     int value = 0; // Int value
210 }
211 
212 // TODO: WidgetModel[] is not implemented. Probably could be a IWidget[]
213 // struct BoxModel {
214 //     string[] _dom_classes; // CSS classes applied to widget DOM element
215 //     enum _model_module = "@jupyter-widgets/controls";
216 //     enum _model_module_version = "1.2.0";
217 //     enum _model_name = "BoxModel";
218 //     enum _view_module = "@jupyter-widgets/controls";
219 //     enum _view_module_version = "1.2.0";
220 //     enum _view_name = "BoxView";
221 //     string box_style = BoxStyle.none; // Use a predefined styling for the box.
222 //     WidgetModel[] children; // List of widget children
223 //     Reference!LayoutModel layout;
224 // }
225 
226 struct ButtonModel {
227     string[] _dom_classes; // CSS classes applied to widget DOM element
228     enum _model_module = "@jupyter-widgets/controls";
229     enum _model_module_version = "1.2.0";
230     enum _model_name = "ButtonModel";
231     enum _view_module = "@jupyter-widgets/controls";
232     enum _view_module_version = "1.2.0";
233     enum _view_name = "ButtonView";
234     string button_style = ButtonStyle.none; // Use a predefined styling for the button.
235     string description; // Button label.
236     bool disabled = false; // Enable or disable user changes.
237     string icon; // Font-awesome icon name, without the 'fa-' prefix.
238     Reference!LayoutModel layout;
239     Reference!ButtonStyleModel style;
240     string tooltip; // Tooltip caption of the button.
241 }
242 
243 struct ButtonStyleModel {
244     enum _model_module = "@jupyter-widgets/controls";
245     enum _model_module_version = "1.2.0";
246     enum _model_name = "ButtonStyleModel";
247     enum _view_module = "@jupyter-widgets/base";
248     enum _view_module_version = "1.0.0";
249     enum _view_name = "StyleView";
250     Nullable!(string) button_color; // Color of the button
251     string font_weight; // Button text font weight.
252 }
253 
254 struct CheckboxModel {
255     string[] _dom_classes; // CSS classes applied to widget DOM element
256     enum _model_module = "@jupyter-widgets/controls";
257     enum _model_module_version = "1.2.0";
258     enum _model_name = "CheckboxModel";
259     enum _view_module = "@jupyter-widgets/controls";
260     enum _view_module_version = "1.2.0";
261     enum _view_name = "CheckboxView";
262     string description; // Description of the control.
263     bool disabled = false; // Enable or disable user changes.
264     bool indent = true; // Indent the control to align with other controls with a description.
265     Reference!LayoutModel layout;
266     Reference!DescriptionStyleModel style; // Styling customizations
267     bool value = false; // Bool value
268 }
269 
270 struct ColorPickerModel {
271     string[] _dom_classes; // CSS classes applied to widget DOM element
272     enum _model_module = "@jupyter-widgets/controls";
273     enum _model_module_version = "1.2.0";
274     enum _model_name = "ColorPickerModel";
275     enum _view_module = "@jupyter-widgets/controls";
276     enum _view_module_version = "1.2.0";
277     enum _view_name = "ColorPickerView";
278     bool concise = false; // Display short version with just a color selector.
279     string description; // Description of the control.
280     bool disabled = false; // Enable or disable user changes.
281     Reference!LayoutModel layout;
282     Reference!DescriptionStyleModel style; // Styling customizations
283     string value = "black"; // The color value.
284 }
285 
286 struct ControllerAxisModel {
287     string[] _dom_classes; // CSS classes applied to widget DOM element
288     enum _model_module = "@jupyter-widgets/controls";
289     enum _model_module_version = "1.2.0";
290     enum _model_name = "ControllerAxisModel";
291     enum _view_module = "@jupyter-widgets/controls";
292     enum _view_module_version = "1.2.0";
293     enum _view_name = "ControllerAxisView";
294     Reference!LayoutModel layout;
295     double value = 0.0; // The value of the axis.
296 }
297 
298 struct ControllerButtonModel {
299     string[] _dom_classes; // CSS classes applied to widget DOM element
300     enum _model_module = "@jupyter-widgets/controls";
301     enum _model_module_version = "1.2.0";
302     enum _model_name = "ControllerButtonModel";
303     enum _view_module = "@jupyter-widgets/controls";
304     enum _view_module_version = "1.2.0";
305     enum _view_name = "ControllerButtonView";
306     Reference!LayoutModel layout;
307     bool pressed = false; // Whether the button is pressed.
308     double value = 0.0; // The value of the button.
309 }
310 
311 // struct ControllerModel {
312 //     string[] _dom_classes; // CSS classes applied to widget DOM element
313 //     enum _model_module = "@jupyter-widgets/controls";
314 //     enum _model_module_version = "1.2.0";
315 //     enum _model_name = "ControllerModel";
316 //     enum _view_module = "@jupyter-widgets/controls";
317 //     enum _view_module_version = "1.2.0";
318 //     enum _view_name = "ControllerView";
319 //     AxisModel[] axes; // The axes on the gamepad.
320 //     ButtonModel[] buttons; // The buttons on the gamepad.
321 //     bool connected = false; // Whether the gamepad is connected.
322 //     int index = 0; // The id number of the controller.
323 //     Reference!LayoutModel layout;
324 //     string mapping; // The name of the control mapping.
325 //     string name; // The name of the controller.
326 //     double timestamp = 0.0; // The last time the data from this gamepad was updated.
327 // }
328 
329 // TODO: Serialisation for Date is not implemented. Could use phobos' DateTime
330 // struct DatePickerModel {
331 //     string[] _dom_classes; // CSS classes applied to widget DOM element
332 //     enum _model_module = "@jupyter-widgets/controls";
333 //     enum _model_module_version = "1.2.0";
334 //     enum _model_name = "DatePickerModel";
335 //     enum _view_module = "@jupyter-widgets/controls";
336 //     enum _view_module_version = "1.2.0";
337 //     enum _view_name = "DatePickerView";
338 //     string description; // Description of the control.
339 //     bool disabled = false; // Enable or disable user changes.
340 //     Reference!LayoutModel layout;
341 //     Reference!DescriptionStyleModel style; // Styling customizations
342 //     Nullable!(Date) value;
343 // }
344 
345 struct DescriptionStyleModel {
346     enum _model_module = "@jupyter-widgets/controls";
347     enum _model_module_version = "1.2.0";
348     enum _model_name = "DescriptionStyleModel";
349     enum _view_module = "@jupyter-widgets/base";
350     enum _view_module_version = "1.0.0";
351     enum _view_name = "StyleView";
352     string description_width; // Width of the description to the side of the control.
353 }
354 
355 // TODO: the source and target fields should probably be a IWidget
356 // struct DirectionalLinkModel {
357 //     enum _model_module = "@jupyter-widgets/controls";
358 //     enum _model_module_version = "1.2.0";
359 //     enum _model_name = "DirectionalLinkModel";
360 //     enum _view_module = "@jupyter-widgets/controls";
361 //     enum _view_module_version = "1.2.0";
362 //     Nullable!(string) _view_name; // Name of the view.
363 //     array source; // The source (widget, 'trait_name') pair
364 //     array target; // The target (widget, 'trait_name') pair
365 // }
366 
367 struct DropdownModel {
368     string[] _dom_classes; // CSS classes applied to widget DOM element
369     enum _model_module = "@jupyter-widgets/controls";
370     enum _model_module_version = "1.2.0";
371     enum _model_name = "DropdownModel";
372     string[] _options_labels; // The labels for the options.
373     enum _view_module = "@jupyter-widgets/controls";
374     enum _view_module_version = "1.2.0";
375     enum _view_name = "DropdownView";
376     string description; // Description of the control.
377     bool disabled = false; // Enable or disable user changes
378     Nullable!(int) index; // Selected index
379     Reference!LayoutModel layout;
380     Reference!DescriptionStyleModel style; // Styling customizations
381 }
382 
383 struct FloatLogSliderModel {
384     string[] _dom_classes; // CSS classes applied to widget DOM element
385     enum _model_module = "@jupyter-widgets/controls";
386     enum _model_module_version = "1.2.0";
387     enum _model_name = "FloatLogSliderModel";
388     enum _view_module = "@jupyter-widgets/controls";
389     enum _view_module_version = "1.2.0";
390     enum _view_name = "FloatLogSliderView";
391     double base = 10.0; // Base for the logarithm
392     bool continuous_update = true; // Update the value of the widget as the user is holding the slider.
393     string description; // Description of the control.
394     bool disabled = false; // Enable or disable user changes
395     Reference!LayoutModel layout;
396     double max = 4.0; // Max value for the exponent
397     double min = 0.0; // Min value for the exponent
398     string orientation = Orientation.horizontal; // Vertical or horizontal.
399     bool readout = true; // Display the current value of the slider next to it.
400     string readout_format = ".3g"; // Format for the readout
401     double step = 0.1; // Minimum step in the exponent to increment the value
402     Reference!SliderStyleModel style;
403     double value = 1.0; // Float value
404 }
405 
406 struct FloatProgressModel {
407     string[] _dom_classes; // CSS classes applied to widget DOM element
408     enum _model_module = "@jupyter-widgets/controls";
409     enum _model_module_version = "1.2.0";
410     enum _model_name = "FloatProgressModel";
411     enum _view_module = "@jupyter-widgets/controls";
412     enum _view_module_version = "1.2.0";
413     enum _view_name = "ProgressView";
414     Nullable!(string) bar_style = Nullable!(string)(BarStyle.none); // Use a predefined styling for the progess bar.
415     string description; // Description of the control.
416     Reference!LayoutModel layout;
417     double max = 100.0; // Max value
418     double min = 0.0; // Min value
419     string orientation = Orientation.horizontal; // Vertical or horizontal.
420     Reference!ProgressStyleModel style;
421     double value = 0.0; // Float value
422 }
423 
424 struct FloatRangeSliderModel {
425     string[] _dom_classes; // CSS classes applied to widget DOM element
426     enum _model_module = "@jupyter-widgets/controls";
427     enum _model_module_version = "1.2.0";
428     enum _model_name = "FloatRangeSliderModel";
429     enum _view_module = "@jupyter-widgets/controls";
430     enum _view_module_version = "1.2.0";
431     enum _view_name = "FloatRangeSliderView";
432     bool continuous_update = true; // Update the value of the widget as the user is sliding the slider.
433     string description; // Description of the control.
434     bool disabled = false; // Enable or disable user changes
435     Reference!LayoutModel layout;
436     double max = 100.0; // Max value
437     double min = 0.0; // Min value
438     string orientation = Orientation.horizontal; // Vertical or horizontal.
439     bool readout = true; // Display the current value of the slider next to it.
440     string readout_format = ".2f"; // Format for the readout
441     double step = 0.1; // Minimum step to increment the value
442     Reference!SliderStyleModel style;
443     double[2] value = [0.0, 1.0]; // Tuple of (lower, upper) bounds
444 }
445 
446 struct FloatSliderModel {
447     string[] _dom_classes; // CSS classes applied to widget DOM element
448     enum _model_module = "@jupyter-widgets/controls";
449     enum _model_module_version = "1.2.0";
450     enum _model_name = "FloatSliderModel";
451     enum _view_module = "@jupyter-widgets/controls";
452     enum _view_module_version = "1.2.0";
453     enum _view_name = "FloatSliderView";
454     bool continuous_update = true; // Update the value of the widget as the user is holding the slider.
455     string description; // Description of the control.
456     bool disabled = false; // Enable or disable user changes
457     Reference!LayoutModel layout;
458     double max = 100.0; // Max value
459     double min = 0.0; // Min value
460     string orientation = Orientation.horizontal; // Vertical or horizontal.
461     bool readout = true; // Display the current value of the slider next to it.
462     string readout_format = ".2f"; // Format for the readout
463     double step = 0.1; // Minimum step to increment the value
464     Reference!SliderStyleModel style;
465     double value = 0.0; // Float value
466 }
467 
468 struct FloatTextModel {
469     string[] _dom_classes; // CSS classes applied to widget DOM element
470     enum _model_module = "@jupyter-widgets/controls";
471     enum _model_module_version = "1.2.0";
472     enum _model_name = "FloatTextModel";
473     enum _view_module = "@jupyter-widgets/controls";
474     enum _view_module_version = "1.2.0";
475     enum _view_name = "FloatTextView";
476     bool continuous_update = false; // Update the value as the user types. If False, update on submission, e.g., pressing Enter or navigating away.
477     string description; // Description of the control.
478     bool disabled = false; // Enable or disable user changes
479     Reference!LayoutModel layout;
480     Nullable!(double) step; // Minimum step to increment the value
481     Reference!DescriptionStyleModel style; // Styling customizations
482     double value = 0.0; // Float value
483 }
484 
485 // TODO: WidgetModel[] is not implemented. Probably could be a IWidget[]
486 // struct HBoxModel {
487 //     string[] _dom_classes; // CSS classes applied to widget DOM element
488 //     enum _model_module = "@jupyter-widgets/controls";
489 //     enum _model_module_version = "1.2.0";
490 //     enum _model_name = "HBoxModel";
491 //     enum _view_module = "@jupyter-widgets/controls";
492 //     enum _view_module_version = "1.2.0";
493 //     enum _view_name = "HBoxView";
494 //     string box_style = BoxStyle.none; // Use a predefined styling for the box.
495 //     WidgetModel[] children; // List of widget children
496 //     Reference!LayoutModel layout;
497 // }
498 
499 struct HTMLMathModel {
500     string[] _dom_classes; // CSS classes applied to widget DOM element
501     enum _model_module = "@jupyter-widgets/controls";
502     enum _model_module_version = "1.2.0";
503     enum _model_name = "HTMLMathModel";
504     enum _view_module = "@jupyter-widgets/controls";
505     enum _view_module_version = "1.2.0";
506     enum _view_name = "HTMLMathView";
507     string description; // Description of the control.
508     Reference!LayoutModel layout;
509     string placeholder = "\u200b"; // Placeholder text to display when nothing has been typed
510     Reference!DescriptionStyleModel style; // Styling customizations
511     string value; // String value
512 }
513 
514 struct HTMLModel {
515     string[] _dom_classes; // CSS classes applied to widget DOM element
516     enum _model_module = "@jupyter-widgets/controls";
517     enum _model_module_version = "1.2.0";
518     enum _model_name = "HTMLModel";
519     enum _view_module = "@jupyter-widgets/controls";
520     enum _view_module_version = "1.2.0";
521     enum _view_name = "HTMLView";
522     string description; // Description of the control.
523     Reference!LayoutModel layout;
524     string placeholder = "\u200b"; // Placeholder text to display when nothing has been typed
525     Reference!DescriptionStyleModel style; // Styling customizations
526     string value; // String value
527 }
528 
529 // TODO: Bytes is not yet defined. Could be ubyte[]. This also requires to implement the buffer_paths part of the ipywidget widget protocol.
530 // struct ImageModel {
531 //     string[] _dom_classes; // CSS classes applied to widget DOM element
532 //     enum _model_module = "@jupyter-widgets/controls";
533 //     enum _model_module_version = "1.2.0";
534 //     enum _model_name = "ImageModel";
535 //     enum _view_module = "@jupyter-widgets/controls";
536 //     enum _view_module_version = "1.2.0";
537 //     enum _view_name = "ImageView";
538 //     string format = "png"; // The format of the image.
539 //     string height; // Height of the image in pixels.
540 //     Reference!LayoutModel layout;
541 //     Bytes value; // The image data as a byte string.
542 //     string width; // Width of the image in pixels.
543 // }
544 
545 struct IntProgressModel {
546     string[] _dom_classes; // CSS classes applied to widget DOM element
547     enum _model_module = "@jupyter-widgets/controls";
548     enum _model_module_version = "1.2.0";
549     enum _model_name = "IntProgressModel";
550     enum _view_module = "@jupyter-widgets/controls";
551     enum _view_module_version = "1.2.0";
552     enum _view_name = "ProgressView";
553     string bar_style = BarStyle.none; // Use a predefined styling for the progess bar.
554     string description; // Description of the control.
555     Reference!LayoutModel layout;
556     int max = 100; // Max value
557     int min = 0; // Min value
558     string orientation = Orientation.horizontal; // Vertical or horizontal.
559     Reference!ProgressStyleModel style;
560     int value = 0; // Int value
561 }
562 
563 struct IntRangeSliderModel {
564     string[] _dom_classes; // CSS classes applied to widget DOM element
565     enum _model_module = "@jupyter-widgets/controls";
566     enum _model_module_version = "1.2.0";
567     enum _model_name = "IntRangeSliderModel";
568     enum _view_module = "@jupyter-widgets/controls";
569     enum _view_module_version = "1.2.0";
570     enum _view_name = "IntRangeSliderView";
571     bool continuous_update = true; // Update the value of the widget as the user is sliding the slider.
572     string description; // Description of the control.
573     bool disabled = false; // Enable or disable user changes
574     Reference!LayoutModel layout;
575     int max = 100; // Max value
576     int min = 0; // Min value
577     string orientation = Orientation.horizontal; // Vertical or horizontal.
578     bool readout = true; // Display the current value of the slider next to it.
579     string readout_format = "d"; // Format for the readout
580     int step = 1; // Minimum step that the value can take
581     Reference!SliderStyleModel style; // Slider style customizations.
582     double[2] value = [0, 1]; // Tuple of (lower, upper) bounds
583 }
584 
585 struct IntSliderModel {
586     string[] _dom_classes; // CSS classes applied to widget DOM element
587     enum _model_module = "@jupyter-widgets/controls";
588     enum _model_module_version = "1.2.0";
589     enum _model_name = "IntSliderModel";
590     enum _view_module = "@jupyter-widgets/controls";
591     enum _view_module_version = "1.2.0";
592     enum _view_name = "IntSliderView";
593     bool continuous_update = true; // Update the value of the widget as the user is holding the slider.
594     string description; // Description of the control.
595     bool disabled = false; // Enable or disable user changes
596     Reference!LayoutModel layout;
597     int max = 100; // Max value
598     int min = 0; // Min value
599     string orientation = Orientation.horizontal; // Vertical or horizontal.
600     bool readout = true; // Display the current value of the slider next to it.
601     string readout_format = "d"; // Format for the readout
602     int step = 1; // Minimum step to increment the value
603     Reference!SliderStyleModel style;
604     int value = 0; // Int value
605 }
606 
607 struct IntTextModel {
608     string[] _dom_classes; // CSS classes applied to widget DOM element
609     enum _model_module = "@jupyter-widgets/controls";
610     enum _model_module_version = "1.2.0";
611     enum _model_name = "IntTextModel";
612     enum _view_module = "@jupyter-widgets/controls";
613     enum _view_module_version = "1.2.0";
614     enum _view_name = "IntTextView";
615     bool continuous_update = false; // Update the value as the user types. If False, update on submission, e.g., pressing Enter or navigating away.
616     string description; // Description of the control.
617     bool disabled = false; // Enable or disable user changes
618     Reference!LayoutModel layout;
619     int step = 1; // Minimum step to increment the value
620     Reference!DescriptionStyleModel style; // Styling customizations
621     int value = 0; // Int value
622 }
623 
624 struct LabelModel {
625     string[] _dom_classes; // CSS classes applied to widget DOM element
626     enum _model_module = "@jupyter-widgets/controls";
627     enum _model_module_version = "1.2.0";
628     enum _model_name = "LabelModel";
629     enum _view_module = "@jupyter-widgets/controls";
630     enum _view_module_version = "1.2.0";
631     enum _view_name = "LabelView";
632     string description; // Description of the control.
633     Reference!LayoutModel layout;
634     string placeholder = "\u200b"; // Placeholder text to display when nothing has been typed
635     Reference!DescriptionStyleModel style; // Styling customizations
636     string value; // String value
637 }
638 
639 // TODO: source and target should probably be a simple struct type
640 // struct LinkModel {
641 //     enum _model_module = "@jupyter-widgets/controls";
642 //     enum _model_module_version = "1.2.0";
643 //     enum _model_name = "LinkModel";
644 //     enum _view_module = "@jupyter-widgets/controls";
645 //     enum _view_module_version = "1.2.0";
646 //     Nullable!(string) _view_name; // Name of the view.
647 //     array source; // The source (widget, 'trait_name') pair
648 //     array target; // The target (widget, 'trait_name') pair
649 // }
650 
651 struct PasswordModel {
652     string[] _dom_classes; // CSS classes applied to widget DOM element
653     enum _model_module = "@jupyter-widgets/controls";
654     enum _model_module_version = "1.2.0";
655     enum _model_name = "PasswordModel";
656     enum _view_module = "@jupyter-widgets/controls";
657     enum _view_module_version = "1.2.0";
658     enum _view_name = "PasswordView";
659     bool continuous_update = true; // Update the value as the user types. If False, update on submission, e.g., pressing Enter or navigating away.
660     string description; // Description of the control.
661     bool disabled = false; // Enable or disable user changes
662     Reference!LayoutModel layout;
663     string placeholder = "\u200b"; // Placeholder text to display when nothing has been typed
664     Reference!DescriptionStyleModel style; // Styling customizations
665     string value; // String value
666 }
667 
668 struct PlayModel {
669     string[] _dom_classes; // CSS classes applied to widget DOM element
670     enum _model_module = "@jupyter-widgets/controls";
671     enum _model_module_version = "1.2.0";
672     enum _model_name = "PlayModel";
673     bool _playing = false; // Whether the control is currently playing.
674     bool _repeat = false; // Whether the control will repeat in a continous loop.
675     enum _view_module = "@jupyter-widgets/controls";
676     enum _view_module_version = "1.2.0";
677     enum _view_name = "PlayView";
678     string description; // Description of the control.
679     bool disabled = false; // Enable or disable user changes
680     int interval = 100; // The maximum value for the play control.
681     Reference!LayoutModel layout;
682     int max = 100; // Max value
683     int min = 0; // Min value
684     bool show_repeat = true; // Show the repeat toggle button in the widget.
685     int step = 1; // Increment step
686     Reference!DescriptionStyleModel style; // Styling customizations
687     int value = 0; // Int value
688 }
689 
690 struct ProgressStyleModel {
691     enum _model_module = "@jupyter-widgets/controls";
692     enum _model_module_version = "1.2.0";
693     enum _model_name = "ProgressStyleModel";
694     enum _view_module = "@jupyter-widgets/base";
695     enum _view_module_version = "1.0.0";
696     enum _view_name = "StyleView";
697     Nullable!(string) bar_color; // Color of the progress bar.
698     string description_width; // Width of the description to the side of the control.
699 }
700 
701 struct RadioButtonsModel {
702     string[] _dom_classes; // CSS classes applied to widget DOM element
703     enum _model_module = "@jupyter-widgets/controls";
704     enum _model_module_version = "1.2.0";
705     enum _model_name = "RadioButtonsModel";
706     string[] _options_labels; // The labels for the options.
707     enum _view_module = "@jupyter-widgets/controls";
708     enum _view_module_version = "1.2.0";
709     enum _view_name = "RadioButtonsView";
710     string description; // Description of the control.
711     bool disabled = false; // Enable or disable user changes
712     Nullable!(int) index; // Selected index
713     Reference!LayoutModel layout;
714     Reference!DescriptionStyleModel style; // Styling customizations
715 }
716 
717 struct SelectModel {
718     string[] _dom_classes; // CSS classes applied to widget DOM element
719     enum _model_module = "@jupyter-widgets/controls";
720     enum _model_module_version = "1.2.0";
721     enum _model_name = "SelectModel";
722     string[] _options_labels; // The labels for the options.
723     enum _view_module = "@jupyter-widgets/controls";
724     enum _view_module_version = "1.2.0";
725     enum _view_name = "SelectView";
726     string description; // Description of the control.
727     bool disabled = false; // Enable or disable user changes
728     Nullable!(int) index; // Selected index
729     Reference!LayoutModel layout;
730     int rows = 5; // The number of rows to display.
731     Reference!DescriptionStyleModel style; // Styling customizations
732 }
733 
734 struct SelectMultipleModel {
735     string[] _dom_classes; // CSS classes applied to widget DOM element
736     enum _model_module = "@jupyter-widgets/controls";
737     enum _model_module_version = "1.2.0";
738     enum _model_name = "SelectMultipleModel";
739     string[] _options_labels; // The labels for the options.
740     enum _view_module = "@jupyter-widgets/controls";
741     enum _view_module_version = "1.2.0";
742     enum _view_name = "SelectMultipleView";
743     string description; // Description of the control.
744     bool disabled = false; // Enable or disable user changes
745     int[] index; // Selected indices
746     Reference!LayoutModel layout;
747     int rows = 5; // The number of rows to display.
748     Reference!DescriptionStyleModel style; // Styling customizations
749 }
750 
751 struct SelectionRangeSliderModel {
752     string[] _dom_classes; // CSS classes applied to widget DOM element
753     enum _model_module = "@jupyter-widgets/controls";
754     enum _model_module_version = "1.2.0";
755     enum _model_name = "SelectionRangeSliderModel";
756     string[] _options_labels; // The labels for the options.
757     enum _view_module = "@jupyter-widgets/controls";
758     enum _view_module_version = "1.2.0";
759     enum _view_name = "SelectionRangeSliderView";
760     bool continuous_update = true; // Update the value of the widget as the user is holding the slider.
761     string description; // Description of the control.
762     bool disabled = false; // Enable or disable user changes
763     int[2] index = [0, 0]; // Min and max selected indices
764     Reference!LayoutModel layout;
765     string orientation = Orientation.horizontal; // Vertical or horizontal.
766     bool readout = true; // Display the current selected label next to the slider
767     Reference!DescriptionStyleModel style; // Styling customizations
768 }
769 
770 struct SelectionSliderModel {
771     string[] _dom_classes; // CSS classes applied to widget DOM element
772     enum _model_module = "@jupyter-widgets/controls";
773     enum _model_module_version = "1.2.0";
774     enum _model_name = "SelectionSliderModel";
775     string[] _options_labels; // The labels for the options.
776     enum _view_module = "@jupyter-widgets/controls";
777     enum _view_module_version = "1.2.0";
778     enum _view_name = "SelectionSliderView";
779     bool continuous_update = true; // Update the value of the widget as the user is holding the slider.
780     string description; // Description of the control.
781     bool disabled = false; // Enable or disable user changes
782     int index = 0; // Selected index
783     Reference!LayoutModel layout;
784     string orientation = Orientation.horizontal; // Vertical or horizontal.
785     bool readout = true; // Display the current selected label next to the slider
786     Reference!DescriptionStyleModel style; // Styling customizations
787 }
788 
789 struct SliderStyleModel {
790     enum _model_module = "@jupyter-widgets/controls";
791     enum _model_module_version = "1.2.0";
792     enum _model_name = "SliderStyleModel";
793     enum _view_module = "@jupyter-widgets/base";
794     enum _view_module_version = "1.0.0";
795     enum _view_name = "StyleView";
796     string description_width; // Width of the description to the side of the control.
797     Nullable!(string) handle_color; // Color of the slider handle.
798 }
799 
800 // TODO: WidgetModel[] is not implemented. Probably could be a IWidget[]
801 // struct TabModel {
802 //     string[] _dom_classes; // CSS classes applied to widget DOM element
803 //     enum _model_module = "@jupyter-widgets/controls";
804 //     enum _model_module_version = "1.2.0";
805 //     enum _model_name = "TabModel";
806 //     JSONValue _titles = {}; // Titles of the pages
807 //     enum _view_module = "@jupyter-widgets/controls";
808 //     enum _view_module_version = "1.2.0";
809 //     enum _view_name = "TabView";
810 //     string box_style = BoxStyle.none; // Use a predefined styling for the box.
811 //     WidgetModel[] children; // List of widget children
812 //     Reference!LayoutModel layout;
813 //     Nullable!(int) selected_index = 0; // The index of the selected page. This is either an integer selecting a particular sub-widget, or None to have no widgets selected.
814 // }
815 
816 struct TextModel {
817     string[] _dom_classes; // CSS classes applied to widget DOM element
818     enum _model_module = "@jupyter-widgets/controls";
819     enum _model_module_version = "1.2.0";
820     enum _model_name = "TextModel";
821     enum _view_module = "@jupyter-widgets/controls";
822     enum _view_module_version = "1.2.0";
823     enum _view_name = "TextView";
824     bool continuous_update = true; // Update the value as the user types. If False, update on submission, e.g., pressing Enter or navigating away.
825     string description; // Description of the control.
826     bool disabled = false; // Enable or disable user changes
827     Reference!LayoutModel layout;
828     string placeholder = "\u200b"; // Placeholder text to display when nothing has been typed
829     Reference!DescriptionStyleModel style; // Styling customizations
830     string value; // String value
831 }
832 
833 struct TextareaModel {
834     string[] _dom_classes; // CSS classes applied to widget DOM element
835     enum _model_module = "@jupyter-widgets/controls";
836     enum _model_module_version = "1.2.0";
837     enum _model_name = "TextareaModel";
838     enum _view_module = "@jupyter-widgets/controls";
839     enum _view_module_version = "1.2.0";
840     enum _view_name = "TextareaView";
841     bool continuous_update = true; // Update the value as the user types. If False, update on submission, e.g., pressing Enter or navigating away.
842     string description; // Description of the control.
843     bool disabled = false; // Enable or disable user changes
844     Reference!LayoutModel layout;
845     string placeholder = "\u200b"; // Placeholder text to display when nothing has been typed
846     Nullable!(int) rows; // The number of rows to display.
847     Reference!DescriptionStyleModel style; // Styling customizations
848     string value; // String value
849 }
850 
851 struct ToggleButtonModel {
852     string[] _dom_classes; // CSS classes applied to widget DOM element
853     enum _model_module = "@jupyter-widgets/controls";
854     enum _model_module_version = "1.2.0";
855     enum _model_name = "ToggleButtonModel";
856     enum _view_module = "@jupyter-widgets/controls";
857     enum _view_module_version = "1.2.0";
858     enum _view_name = "ToggleButtonView";
859     string button_style = ButtonStyle.none; // Use a predefined styling for the button.
860     string description; // Description of the control.
861     bool disabled = false; // Enable or disable user changes.
862     string icon; // Font-awesome icon.
863     Reference!LayoutModel layout;
864     Reference!DescriptionStyleModel style; // Styling customizations
865     string tooltip; // Tooltip caption of the toggle button.
866     bool value = false; // Bool value
867 }
868 
869 struct ToggleButtonsModel {
870     string[] _dom_classes; // CSS classes applied to widget DOM element
871     enum _model_module = "@jupyter-widgets/controls";
872     enum _model_module_version = "1.2.0";
873     enum _model_name = "ToggleButtonsModel";
874     string[] _options_labels; // The labels for the options.
875     enum _view_module = "@jupyter-widgets/controls";
876     enum _view_module_version = "1.2.0";
877     enum _view_name = "ToggleButtonsView";
878     Nullable!(string) button_style = Nullable!(string)(ButtonStyle.none); // Use a predefined styling for the buttons.
879     string description; // Description of the control.
880     bool disabled = false; // Enable or disable user changes
881     string[] icons; // Icons names for each button (FontAwesome names without the fa- prefix).
882     Nullable!(int) index; // Selected index
883     Reference!LayoutModel layout;
884     Reference!ToggleButtonsStyleModel style;
885     string[] tooltips; // Tooltips for each button.
886 }
887 
888 struct ToggleButtonsStyleModel {
889     enum _model_module = "@jupyter-widgets/controls";
890     enum _model_module_version = "1.2.0";
891     enum _model_name = "ToggleButtonsStyleModel";
892     enum _view_module = "@jupyter-widgets/base";
893     enum _view_module_version = "1.0.0";
894     enum _view_name = "StyleView";
895     string button_width; // The width of each button.
896     string description_width; // Width of the description to the side of the control.
897     string font_weight; // Text font weight of each button.
898 }
899 
900 // TODO: WidgetModel[] is not implemented. Probably could be a IWidget[]
901 // struct VBoxModel {
902 //     string[] _dom_classes; // CSS classes applied to widget DOM element
903 //     enum _model_module = "@jupyter-widgets/controls";
904 //     enum _model_module_version = "1.2.0";
905 //     enum _model_name = "VBoxModel";
906 //     enum _view_module = "@jupyter-widgets/controls";
907 //     enum _view_module_version = "1.2.0";
908 //     enum _view_name = "VBoxView";
909 //     string box_style = BoxStyle.none; // Use a predefined styling for the box.
910 //     WidgetModel[] children; // List of widget children
911 //     Reference!LayoutModel layout;
912 // }
913 
914 struct ValidModel {
915     string[] _dom_classes; // CSS classes applied to widget DOM element
916     enum _model_module = "@jupyter-widgets/controls";
917     enum _model_module_version = "1.2.0";
918     enum _model_name = "ValidModel";
919     enum _view_module = "@jupyter-widgets/controls";
920     enum _view_module_version = "1.2.0";
921     enum _view_name = "ValidView";
922     string description; // Description of the control.
923     bool disabled = false; // Enable or disable user changes.
924     Reference!LayoutModel layout;
925     string readout = "Invalid"; // Message displayed when the value is False
926     Reference!DescriptionStyleModel style; // Styling customizations
927     bool value = false; // Bool value
928 }
929 
930 struct OutputModel {
931     string[] _dom_classes; // CSS classes applied to widget DOM element
932     enum _model_module = "@jupyter-widgets/output";
933     enum _model_module_version = "1.0.0";
934     enum _model_name = "OutputModel";
935     enum _view_module = "@jupyter-widgets/output";
936     enum _view_module_version = "1.0.0";
937     enum _view_name = "OutputView";
938     Reference!LayoutModel layout;
939     string msg_id; // Parent message id of messages to capture
940     JSONValue[] outputs; // The output messages synced from the frontend.
941 }
942 
943 enum isModel(alias T) = __traits(compiles, T._model_module);
944 enum isModel(T) = __traits(compiles, T._model_module);
945 
946 JSONValue toJSONValue(T)(ref T field) {
947     static if (is(T : Reference!P, P))
948         return JSONValue(field.value);
949     else static if (isModel!T)
950         return field.serialize();
951     else static if (is(T : Nullable!S, S)) {
952         if (field.isNull)
953             return JSONValue(null);
954         return field.get.toJSONValue();
955     } else
956         return JSONValue(field);
957 }
958 
959 T fromJSONValue(T)(in ref JSONValue value) {
960     static if (is (T : int[2])) {
961         int[2] range = [cast(int)value[0].integer, cast(int)value[1].integer];
962         return range;
963     }
964     static if (is (T : double[2])) {
965         double[2] range = [cast(double)value[0].floating, cast(double)value[1].floating];
966         return range;
967     }
968     static if (is(T : Reference!P, P))
969         return Reference!P(value.str);
970     static if (is(T == double)) {
971         if (value.type == JSONType.integer)
972             return cast(float)value.integer();
973         return value.floating();
974     } else static if (is(T == int))
975         return cast(int)value.integer();
976     else static if (is(T == immutable(char)[]))
977         return value.str();
978     else static if (is(T == string))
979         return value.str();
980     else static if (is(T == bool))
981         return value.boolean();
982     else static if (is(T == enum))
983         return cast(T)value.str();
984     else static if (is(T == JSONValue[]))
985         return (() @trusted => value.array)().dup;
986     else static if (is(T == P[], P))
987         return (() @trusted => value.array)().map!(value => value.fromJSONValue!P).array();
988     else static if (is(T == Nullable!P, P)) {
989         if (value.isNull)
990             return Nullable!P();
991         return Nullable!P(value.fromJSONValue!P);
992     }
993     static assert("Don't know how to deserialize "~T.stringof);
994 }
995 
996 JSONValue serialize(T)(ref T obj) if (isModel!T) {
997     JSONValue data;
998     JSONValue state;
999     state["_model_module"] = obj._model_module;
1000     state["_model_module_version"] = obj._model_module_version;
1001     state["_model_name"] = obj._model_name;
1002     state["_view_module"] = obj._view_module;
1003     state["_view_module_version"] = obj._view_module_version;
1004     state["_view_name"] = obj._view_name;
1005 
1006     foreach (idx, field; obj.tupleof) {
1007         state[__traits(identifier, obj.tupleof[idx])] = field.toJSONValue();
1008     }
1009     data["state"] = state;
1010     data["buffer_paths"] = parseJSON(`[]`); // NOTE: we need to use buffer_paths whenever we move raw bytes
1011     return data;
1012  }
1013 
1014 @safe unittest {
1015     FloatSliderModel slider;
1016     slider.serialize();
1017 }
1018 
1019 void update(T)(ref T state, JSONValue newState, JSONValue buffer_paths) if (isModel!T) {
1020     if (newState.type != JSONType.object)
1021         throw new Error("Excepted JSON object");
1022     const object = (() @trusted => newState.object)();
1023     foreach (idx, field; state.tupleof) {
1024         enum FieldName = __traits(identifier, state.tupleof[idx]);
1025         alias FieldType = typeof(state.tupleof[idx]);
1026         if (auto p = FieldName in object) {
1027             static if (isModel!(FieldType)) {
1028                 __traits(getMember, state, FieldName).update(*p, buffer_paths);
1029             } else
1030                 __traits(getMember, state, FieldName) = (*p).fromJSONValue!(FieldType);
1031         }
1032     }
1033  }
1034 
1035 @safe unittest {
1036     FloatSliderModel slider;
1037     slider.update(parseJSON(`{"max":300.0}`), parseJSON("{}"));
1038     assert(slider.max == 300.0);
1039 }
1040 
1041 alias getModuleMember(string name) = __traits(getMember, mixin(__MODULE__), name);
1042 enum filterSelf(string name) = name != "AllModels";
1043 alias AllModels = Filter!(isModel, staticMap!(getModuleMember, Filter!(filterSelf,  __traits(allMembers, mixin(__MODULE__)))));